package kr.co.handysoft.smartPolice.server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.SocketException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;

import kr.co.handysoft.common.compress.Archiving;
import kr.co.handysoft.common.registry.SmartPoliceRegistry;
import kr.co.handysoft.project.smartPolice.composite.WatchingFileThreadMonitorComposite;
import kr.co.handysoft.smartPolice.vo.Constant;
import kr.co.handysoft.smartPolice.vo.PassData;
import kr.co.handysoft.smartPolice.vo.PassDataProcessResult;
import net.sf.json.JSONObject;

import org.apache.commons.codec.digest.DigestUtils;
import org.jdom.Element;

public class FileInformationSenderHandler {

	private String success;
	private String fail;
	private String id;
	private String idKor;
	private Socket socket;
	private File tmpFile;
	private BufferedWriter out;
	private BufferedReader in;
	private Element directoryInfo;
	private boolean startUpdateFlag = true;
	private JSONObject infoObj;

	public FileInformationSenderHandler(Socket socket, Element directoryInfo) {
		
		this.socket = socket;
		this.directoryInfo = directoryInfo;
		infoObj = new JSONObject();
		infoObj.put("zone", this.directoryInfo.getAttributeValue("zone"));
		infoObj.put("zoneKor", this.directoryInfo.getAttributeValue("zoneKor"));
		infoObj.put("kor", this.directoryInfo.getAttributeValue("kor"));
		infoObj.put("part", this.directoryInfo.getAttributeValue("part"));
		
		try {
			if (this.socket != null){ sendServerInformation(); }
			this.tmpFile = File.createTempFile("~AIIT", ".tmp");
			out = new BufferedWriter(new FileWriter(this.tmpFile));
			in = new BufferedReader(new FileReader(this.tmpFile));
			System.out.println("tmpFile : " + this.tmpFile.getAbsolutePath());
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	} 

	private void sendServerInformation() {
		OutputStream os_socket;
		
		try {
			os_socket = this.socket.getOutputStream();
			InputStream is_socket = this.socket.getInputStream();
			
			BufferedWriter bufferW = new BufferedWriter(new OutputStreamWriter(os_socket));
			BufferedReader bufferR = new BufferedReader(new InputStreamReader(is_socket));
			bufferW.flush(); 
			String str = bufferR.readLine();
			if (str.equals("getInformation")){
				bufferW.write(infoObj.toString() + "\r\n");
				bufferW.flush();
				String procResult = bufferR.readLine();
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	public void invoke(File[] tgrFileArray, String successFolder, String failFolder, String part, String command) {
		
		success = successFolder;
		fail = failFolder;
		
		if (this.socket == null || this.socket.isClosed()){
			this.socket = SmartPoliceRegistry.getSocket();
			if (this.socket != null){ sendServerInformation(); }
		}
		
		WatchingFileThreadMonitorComposite updateTarget = (WatchingFileThreadMonitorComposite)SmartPoliceRegistry.getUpdateTarget(part);
		PassDataProcessResult result = new PassDataProcessResult(id, idKor, command);
		ArrayList<PassData> fileCollection = (ArrayList<PassData>)result.get(Constant.FILES);
		
		if (tgrFileArray != null){
			
			for (File tgrFile : tgrFileArray){
				processFile(tgrFile, fileCollection);
			}
			
			if (fileCollection.size() > 0){
				
				JSONObject resultJSON = JSONObject.fromObject(result);
				String fileProcessResultString = Archiving.send(resultJSON.toString()) + "\r\n";
				addUpdateCompositeContents(updateTarget, fileProcessResultString, resultJSON);
				
				try {
					
					if (this.socket != null){
						
						communicateServer(fileProcessResultString);
						
						if (this.socket != null && tmpFile.length() > 0){
							
							String lineString = null;
							
							while ((lineString = in.readLine()) != null) {
								communicateServer(lineString + "\r\n");
							}
							out.close(); in.close();
							this.tmpFile = File.createTempFile("~AIIT", ".tmp");
							out = new BufferedWriter(new FileWriter(this.tmpFile));
							in = new BufferedReader(new FileReader(this.tmpFile));
								
						}
						
					}else{
						
						writeFile(fileProcessResultString);
						
					}
				} catch (SocketException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}			
		}
	}


	private void addUpdateCompositeContents(
			WatchingFileThreadMonitorComposite updateTarget,
			String fileProcessResultString, JSONObject resultJSON) {

		if (updateTarget != null){
			updateTarget.addRoot(DigestUtils.md5Hex(fileProcessResultString), resultJSON);
		}
	}

	private void processFile(File tgrFile, ArrayList<PassData> result) {
		moveFile(tgrFile, success, result);
	}

	private void moveFile(File tgrFile, String movePath, ArrayList<PassData> collection) {
		
		PassData procFile = new PassData(tgrFile, this.success, this.directoryInfo.getAttributeValue("zone"));
		String fileName = procFile.getPathString() + "/" + tgrFile.getName() ;
		if (copyFile(tgrFile, new File(fileName))){
			
			if (collection != null){
				collection.add(procFile);
			}
			
			tgrFile.delete();
		}
	}

	private void writeFile(String fileProcessResultString) {
	
		try {
			out.write(fileProcessResultString);
			out.flush();
		} catch (IOException e) {}
	}
	
	private void communicateServer(String fileProcessResultString) {
		
		OutputStream os_socket;
		
		try {
		
			os_socket = this.socket.getOutputStream();
			InputStream is_socket = this.socket.getInputStream();
			
			BufferedWriter bufferW = new BufferedWriter(new OutputStreamWriter(os_socket));
			BufferedReader bufferR = new BufferedReader(new InputStreamReader(is_socket));
			bufferW.write(fileProcessResultString);
			bufferW.flush(); 
			bufferR.readLine();
			
		} catch (IOException e) {
			this.socket = null;
			writeFile(fileProcessResultString);
		}

	}
	
	private boolean copyFile(File sourceFile, File destFile)  {
		 FileChannel source = null;
		 FileChannel destination = null;
		 
		 try {			 
			 source = new FileInputStream(sourceFile).getChannel();
			 destination = new FileOutputStream(destFile).getChannel();
			 destination.transferFrom(source, 0, source.size());
		 } catch (FileNotFoundException e) {
			 return false;
		 } catch (IOException e) {
			 return false;
		 }finally {
			 if(source != null)
				try {
					source.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			 if(destination != null)
				try {
					destination.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		 }
		 
		 return true;
	}

	public void setSystemId(String sId, String sIdKor) {
		id = sId;
		idKor = sIdKor;
	}

}
